#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#define SIZE 4096
#define NONE_FLUSH 1<<1
#define LINE_FLUSH 1<<2
#define FULL_FLUSH 1<<3

typedef struct my_file{
    int fileno;
    char buf[SIZE];
    size_t pos;
    size_t cap;
    int flush_mode;
}my_FILE;

void print_debug(my_FILE* stream)
{
    printf("stream->fileno=%d\n", stream->fileno);
    printf("stream->pos=%zd\n", stream->pos);
    printf("stream->cap=%zd\n", stream->cap);
    printf("\n"); 
}

my_FILE* my_fopen(const char *filename, const char *mode)
{
    my_FILE* file = (my_FILE*)malloc(sizeof(my_FILE));
    int flag = 0;
    int fd = -1;
    if(strcmp(mode, "w") == 0)
    {
        flag = O_WRONLY | O_CREAT | O_TRUNC;

    }
    else if(strcmp(mode, "r") == 0)
    {
        flag = O_RDONLY;
    }
    else if(strcmp(mode, "a") == 0)
    {
        flag = O_WRONLY | O_CREAT | O_APPEND;
    }
    else 
    {
        return NULL;
    }

    if((flag & O_WRONLY) == O_WRONLY)
    {
        fd = open(filename, flag, 0666);
    }
    else 
    {
        fd = open(filename, flag);
    }
    if(fd < 0)
    {
        perror("open");
        return NULL;
    }
    file->fileno = fd;
    file->pos = 0;
    file->cap = SIZE;
    file->flush_mode = LINE_FLUSH;
    return file;
}


void my_fflush(my_FILE* stream)
{
    if(stream->pos)
    {
        write(stream->fileno, stream->buf, stream->pos);
        stream->pos = 0;      
    }
}

size_t my_fwrite(const void* buf, size_t size, my_FILE* stream)
{
    //size_t total = size;
    //size_t tail = 0;
    //if(stream->pos + total > stream->cap)
    //{
    //    tail = stream->cap - stream->pos;
    //    memcpy(stream->buf+stream->pos, buf, tail);
    //    my_fflush(stream);
    //    total -= tail;
    //}
    //if(total)
    //    memcpy(stream->buf+stream->pos, (char*)buf+tail, total);
    //stream->pos += total;
    
    size_t i = 0;
    for(; i<size; i++)
    {
        stream->buf[stream->pos++] = ((const char*)buf)[i];
        if(stream->pos == stream->cap)
            my_fflush(stream);
        if(stream->flush_mode == LINE_FLUSH && stream->buf[stream->pos-1] == '\n')
            my_fflush(stream);
    }
    return size;
}

int my_fclose(my_FILE* stream)
{
    my_fflush(stream);
    int ret = close(stream->fileno);
    free(stream);
    return ret;
}

int main()
{
    char buf[64];
    my_FILE* fp = my_fopen("log.txt", "w");
    int cnt = 5;
    while(cnt)
    {
        //snprintf(buf, sizeof(buf)-1, "hello world%d", cnt--);
        snprintf(buf, sizeof(buf)-1, "hello world%d\n", cnt--);
        my_fwrite(buf, strlen(buf), fp);
        print_debug(fp);
        sleep(2);
    }
    my_fclose(fp);

    return 0;
}
